package com.servoy.r3.plugins;

import java.io.File;
import java.sql.Connection;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
import java.util.ArrayList;
import java.util.HashMap;

import com.servoy.j2db.plugins.IClientPluginAccess;
import com.servoy.j2db.util.Debug;

public class JRXMLProvider {

	public static final String XMLSAMPLEDATA_FILENAME = "reportsdata.xml";
	// public static final String XMLREPORT_XMLED = ".xmled";
	public static final String XMLREPORT_XMLED = "";

	private String fileName;
	//private IJasperReportsService jasperReportService = null;
	//private IClientPluginAccess application;
	private Connection connection= null;

	private JRXMLDocumentProxy originalDocument = null;

	private ArrayList filesToZip = new ArrayList();

	private HashMap parameters = new HashMap();

	public JRXMLProvider(Connection connection, String fileName,
			HashMap map) throws Exception {

		this.fileName = fileName;
		this.connection = connection;
		this.parameters = map;

		/*
		// Get the server service
		Debug.trace("JasperTrace: JasperReport initialize");
		// create if not yet created
		if (jasperReportService == null) {
			try {
				jasperReportService = (IJasperReportsService) application
						.getServerService("servoy.IJasperReportService");
			} catch (Exception e) {
				Debug.error(e);
				throw new Exception(
						"Jasper Exception: Cannot connect to service-server");
			}
		}
		*/

		originalDocument = new JRXMLDocumentProxy(/*this.application,*/
				this.fileName, this.parameters);
	}

	public void setFilesToZipArray(ArrayList list) {
		this.filesToZip = list;
	}

	public String getFilename() {
		return this.fileName;
	}

	public void appendXMLSampleData(String dbalias, int rows,
			XMLSampleData dataobject) throws Exception{

		try {
			String sqlQuery = originalDocument.getQueryString(true);

			System.out.println("Query = " + sqlQuery);

			// Get the database connection for the user supplied alias and
			// execute the query
			
			//Connection connection = null;
			//connection = jasperReportService.getDBConnection(dbalias);
			Statement st = connection.createStatement();
			ResultSet rs = st.executeQuery(sqlQuery);

			// Create the report xml structure
			dataobject.createRaportData(rs, rows, this.fileName);

			// Create the xml structure for the reports subreports.
			ArrayList subs = originalDocument.getSubreports();
			
			//for (JRXMLSubreport s : subs) {
			for (int i=0; i<subs.size(); i++){
				JRXMLSubreport s = (JRXMLSubreport)subs.get(i);

				String dir = Utils.getPathFromFileName(this.fileName);
				String path = Utils.getAbsoluteFileName(dir, s
						.getSubreportFilename(true));

				JRXMLProvider provider = new JRXMLProvider(this.connection,
						path, parameters);

				provider.appendXMLSampleData(dbalias, rows, dataobject);
			}

		} catch (SQLException e) {
			Debug.error(e);
			throw e;
		} catch (Exception ex) {
			Debug.error(ex);
			throw ex;
		}
	}

	private String getXMLSampleData(String dbalias, int rows,
			String destinationfilename) throws Exception{

		String result = null;

		try {
			// Create the sample xml data object.
			XMLSampleData xmlsample = new XMLSampleData();

			// Append the data for the report and subreports.
			this.appendXMLSampleData(dbalias, rows, xmlsample);

			// Serialize the document.
			result = xmlsample.serializeData(destinationfilename);

			// Save the path in the list of files to be archived.
			this.filesToZip.add(destinationfilename);
		} catch (Exception ex) {
			Debug.error(ex);
			throw ex;
		}

		return result;
	}

	private String getReportLinkedToXmlData(String destinationPath) throws Exception{
		String result = null;

		JRXMLDocumentProxy destinationDoc = originalDocument.Duplicate();

		// Update the query string to match the xml connection.
		destinationDoc.updateQueryStringForXML();

		// Update the field tags to match xPath addresses in description.
		destinationDoc.updateFieldsForXML();

		// Update subreports.
		destinationDoc.updateSubreportsForXML();

		// Serialize the document.
		String destfname = destinationPath
				+ Utils.getModifiedFileName(this.fileName, XMLREPORT_XMLED);
		result = destinationDoc.serializeData(destfname);

		// Add the document path to the list of files to be archived.
		this.filesToZip.add(destfname);

		// Add resource bundle documents to the list of files to be archived.
		File[] rbList = Utils.getResourceBundleFiles(Utils
				.getPathFromFileName(this.fileName), originalDocument
				.getResourceBundle());
		Utils.copyResourceBundleFilesAndAddToZipList(rbList, destinationPath,
				this.filesToZip);

		try {
			ArrayList subs = originalDocument.getSubreports();
			//for (JRXMLSubreport s : subs) {
			
			for (int i=0; i<subs.size(); i++){
				JRXMLSubreport s = (JRXMLSubreport)subs.get(i);
				
				String dir = Utils.getPathFromFileName(this.fileName);
				String path = Utils.getAbsoluteFileName(dir, s
						.getSubreportFilename(true));

				JRXMLProvider provider = new JRXMLProvider(this.connection,
						path, parameters);
				provider.setFilesToZipArray(this.filesToZip);

				provider.getReportLinkedToXmlData(destinationPath);
			}
		} catch (Exception ex) {
			Debug.error(ex);
			throw ex;
		}

		return result;
	}

	private String getReportUnlinkedFromXmlData(String destinationPath)
			throws Exception {

		String result = null;

		// Get JR sql query
		String sqlQuery = originalDocument.getQueryString(false);

		// Get the report filename that was xmled.
		String xmledOriginalFile = destinationPath
				+ Utils.getNameWithoutExtensionFromFileName(this.fileName)
				+ XMLREPORT_XMLED + "."
				+ Utils.getExtensionFromFileName(this.fileName);

		// Revert the query to sql
		JRXMLDocumentProxy xmlModifiedDoc = new JRXMLDocumentProxy(/*application,*/
				xmledOriginalFile, parameters);
		xmlModifiedDoc.updateQueryStringForSQL(sqlQuery);

		// Remove fields description from the document
		xmlModifiedDoc.updateFieldsforSQL();

		// Update the subreports.
		xmlModifiedDoc.updateSubreportsForSQL(originalDocument
				.getSubreportsFilenames());

		// Serialize the doc
		result = xmlModifiedDoc.serializeData(this.fileName);

		// Copy archibed resource bundle files over the original files
		File[] rbList = Utils.getResourceBundleFiles(destinationPath,
				originalDocument.getResourceBundle());
		Utils.copyResourceBundleFilesAndAddToZipList(rbList, Utils
				.getPathFromFileName(this.fileName), null);

		try {
			ArrayList subs = originalDocument.getSubreports();
			//for (JRXMLSubreport s : subs) {
			
			for (int i=0; i<subs.size(); i++){
				JRXMLSubreport s = (JRXMLSubreport)subs.get(i);
				
				String dir = Utils.getPathFromFileName(this.fileName);
				String path = Utils.getAbsoluteFileName(dir, s
						.getSubreportFilename(true));

				JRXMLProvider provider = new JRXMLProvider(this.connection,
						path, parameters);

				provider.getReportUnlinkedFromXmlData(destinationPath);
			}
		} catch (Exception ex) {
			Debug.error(ex);
			throw ex;
		}

		return result;

	}

	public void getXmledData(String dbalias, int rows, String destFilename) throws Exception{

		// Create the temp dir where all the files will be stored for zipping.
		String destinationPath = Utils.getTempDir(destFilename);
		File tempdir = new File(destinationPath);
		tempdir.mkdir();

		// Save the sample data.
		this.getXMLSampleData(dbalias, rows, destinationPath
				+ XMLSAMPLEDATA_FILENAME);

		// Gets the reports linked to xml.
		this.getReportLinkedToXmlData(destinationPath);

		// Zip the directory.
		Utils.zipFiles(destFilename, this.filesToZip);

		// Delete the temp directory.
		Utils.deleteDirectory(tempdir);
	}

	public void getSqledData(String xmledZipFile) throws Exception {

		// Create the temp dir where all the files will be stored for unzipping.
		String destinationPath = Utils.getTempDir(xmledZipFile);
		File tempdir = new File(destinationPath);
		tempdir.mkdir();

		// Unzip the file to the temp dir.
		Utils.unzipFile(xmledZipFile, destinationPath);

		// Update the xmled reports to sql.
		this.getReportUnlinkedFromXmlData(destinationPath);

		// Delete the temp directory.
		Utils.deleteDirectory(tempdir);
	}
}
